package libtool65.o65;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Arrays;

public class Module {
	private Header header = new Header();
	private Options options = new Options();
	private CodeBlock text_block = new CodeBlock();
	private CodeBlock data_block = new CodeBlock();
	private References references = new References();
	private RelocationTable text_table = new RelocationTable();
	private RelocationTable data_table = new RelocationTable();
	private ExportDefinitions exports = new ExportDefinitions();

	public void read(InputStream file) throws IOException, O65Exception {
		header.read(file);
		options.read(file);
		text_block.read(file, header.getTextSegment());
		data_block.read(file, header.getDataSegment());
		references.read(file, header.getMode());
		text_table.read(file, header.getMode());
		data_table.read(file, header.getMode());
		exports.read(file, header.getMode());
	}

	public void dumpInfo(PrintStream out) {
		out.println("----< HEADER >--------------------------");
		header.dumpInfo(out);
		out.println("----< OPTIONS >-------------------------");
		options.dumpInfo(out);
		out.println("----< REFERENCES >----------------------");
		references.dumpInfo(out);
		out.println("----< TEXT RELOCATION >-----------------");
		text_table.dumpInfo(out);
		out.println("----< DATA RELOCATION >-----------------");
		data_table.dumpInfo(out);
		out.println("----< EXPORTS >-------------------------");
		exports.dumpInfo(out);
		out.println("----------------------------------------");
	}

	public References getReferences() {
		return references;
	}

	public ExportDefinitions getExports() {
		return exports;
	}

	public int getCodeSize() {
		if (header.getMode().isBssZero())
			return header.getTextSegment().getSize()+header.getDataSegment().getSize()+header.getBssSegment().getSize();
		else
			return header.getTextSegment().getSize()+header.getDataSegment().getSize();
	}

	public int getTotalCodeSize() {
		return header.getTextSegment().getSize()+header.getDataSegment().getSize()+header.getBssSegment().getSize();
	}
	
	public int getTextOffset() {
		return 0;
	}

	public int getDataOffset() {
		return header.getTextSegment().getSize();
	}

	public int getBssOffset() {
		return getDataOffset() + header.getBssSegment().getSize();
	}

	public boolean isBssZeroFilled() {
		return header.getMode().isBssZero();
	}

	public int copyText(byte[] code_block, int current_offset) {
		return text_block.copyTo(code_block, current_offset);
	}

	public int copyData(byte[] code_block, int current_offset) {
		return data_block.copyTo(code_block, current_offset);
	}

	public int copyBss(byte[] code_block, int current_offset) {
		if (header.getMode().isBssZero())
		{
			int next_offset = current_offset + header.getBssSegment().getSize();
			Arrays.fill(code_block, current_offset, next_offset, (byte)0);
			return next_offset; 
		}
		return current_offset;
	}

	public RelocationTable getDataRelocations() {
		return data_table;
	}

	public RelocationTable getTextRelocations() {
		return text_table;
	}

	public int getTextBase() {
		return header.getTextSegment().getBase();
	}

	public int getDataBase() {
		return header.getDataSegment().getBase();
	}

	public int getBssBase() {
		return header.getBssSegment().getBase();
	}

	public int getZpSize() {
		return header.getZpSegment().getSize();
	}

	public int getZpBase() {
		return header.getZpSegment().getBase();
	}

	public String getImportLabel(int index) {
		return references.getLabel(index);
	}

	public ExportDefinition getExportDefinition(String label) {
		return exports.getDefinition(label);
	}
}
